"""
所有的元素类和功能类模块
"""

import random
import pygame
from . import setting as st
from game_file.tool import *


screen_list = []  # 创建一个显示列表全局
bullet_list = []  # 创建一个显示子弹的全局列表
bullet_del = []  # 创建一个该删除的元素列表
num1 = 0  # 创建一个爆炸效果的计数器


class Obj(object):
    """创建一个父类1"""
    # 构造位置属性
    def __init__(self, x, y, screen, filename):
        self.x = x
        self.y = y
        self.screen = screen
        self.name = filename
        self.image_1 = pygame.image.load_extended(self.name)  # 加载背景图片
        self.rect = self.image_1.get_rect()  # 获取图片的外接矩形

    def draw(self):  # 设置绘制的功能
        pass


class ScriptBase(Obj):
    """创建一个文字基类"""

    def __init__(self, x, y, screen, script, size,
                 filename=st.SCRIPT, color=(255, 255, 255),
                 bool_sc=True, bg_script=None):
        """
        构造函数，初始化文字的位置x,y，显示的窗口screen，文字script，
        字体大小size，字体的TTF文件filename，字体的颜色color,默认开启抗锯齿True,
        不定长参数为是否设置字的背景bg_script
        """
        self.x = x
        self.y = y
        self.screen = screen
        self.script = script
        self.size = size
        self.name = filename
        self.color = color
        self.bool_sc = bool_sc
        self.bg_script = bg_script

    def sc_act(self):
        """创建文字的函数"""
        # 创建一个文字对象
        my_font = pygame.font.Font(self.name, self.size)
        # 文件对象的显示参数
        text_surface = my_font.render(self.script, self.bool_sc,
                                      self.color, self.bg_script)
        return text_surface

    def draw(self):
        text = self.sc_act()
        # 显示创建的文字对象
        self.screen.blit(text, (self.x, self.y))

    def change_size(self):
        """文字的效果，如大小闪烁，移动变化等"""
        pass

    def change_color(self):
        pass


class ScriptNew(ScriptBase):
    """创建基本的文字"""
    def __init__(self, x, y, screen, script, size, *args):
        super().__init__(x, y, screen, script, size, *args)
        # 创建一个文字对象
        self.my_font = pygame.font.Font(self.name, self.size)
        # 文件对象的显示参数
        self.text_surface = self.my_font.render(self.script, self.bool_sc,
                                                self.color, self.bg_script)

    def draw(self):
        # 显示创建的文字对象
        self.screen.blit(self.text_surface, (self.x, self.y))


class ScriptLong(ScriptBase):
    """创建大段依次显示的文字"""
    def __init__(self, x, y, screen, script, size, *args):
        super().__init__(x, y, screen, script, size, *args)
        # 创建一个文字对象
        self.my_font = pygame.font.Font(self.name, self.size)
        self.fps = 0
        # 单个文字对象
        self.t = None
        # 创建一个文字图像列表
        self.text = []
        for x in range(len(self.script)):  # 创建单个的文字图像
            t = self.my_font.render(self.script[:x+1], self.bool_sc,
                                    self.color, self.bg_script)
            self.text.append(t)
        self.it = iter(self.text)  # 获得迭代器

    def draw(self):
        self.fps += 1
        if self.fps % 20 == 0:  # 每隔5帧数显示一个文字
            try:
                self.t = next(self.it)
            except StopIteration:
                pass
        if self.t:  # 如果对象不为空
            self.screen.blit(self.t, (self.x, self.y))


class ScriptMove(ScriptBase):
    """创建一个的大小变化和闪烁效果"""
    def __init__(self, x, y, screen, script, size, *args):
        super().__init__(x, y, screen, script, size, *args)
        # 创建一个闪烁速度的计数器
        self.fps = 0
        # 字体尺寸最小
        self.least = 80
        # 字体最大
        self.max = size
        # 设置变化的颜色
        self.list_color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]

    def draw(self):
        self.fps += 1
        super().draw()
        if self.fps >= 20:  # 20帧数后开始变化
            self.change_size()  # 改变文字大小
            self.change_color()  # 改变文字颜色

    def change_size(self):
        """重写父类的方法"""
        # print("change执行了")
        if self.fps % 2 == 0 and self.size > self.least:  # 每过5帧数执行一次
            self.size -= 2
            self.x += 1
            self.y += 1
            # if self.size <= self.least:  # 达到最小时还原大小
            #     self.size = self.max

    def change_color(self):
        """文字颜色红绿蓝三色变化"""
        if self.fps % 5 == 0:
            ran = random.randint(0, 2)
            self.color = self.list_color[ran]


class ScriptEnd(ScriptBase):
    """创建一个文字由小到大的效果"""
    def __init__(self, x, y, screen, script, size, *args):
        super().__init__(x, y, screen, script, size, *args)
        # 创建一个闪烁速度的计数器
        self.fps = 0

    def change_size(self):
        if self.fps % 2 == 0 and self.size < 180:  # 每过5帧数执行一次
            self.size += 3
            self.x -= 1
            self.y -= 1

    def draw(self):
        self.fps += 1
        super().draw()
        self.change_size()


class ButtonGame(Obj):
    """创建一个游戏开始按钮"""

    def __init__(self, x, y, screen, list_image):
        self.x = x
        self.y = y
        self.screen = screen
        self.images = []  # 按钮的图片群
        self.fps = 0  # 按钮显示的计数器
        self.ran = 0  # 图片下标
        for image in list_image:  # 所有图片全部加载
            self.images.append(pygame.image.load_extended(image))

    def draw(self):
        self.fps += 1
        if self.fps % 10 == 0:  # 每过15帧显示一张按钮图片
            self.ran += 1
            if self.ran > 3:
                self.ran = 0
        self.screen.blit(self.images[self.ran], (self.x, self.y))  # 循环显示背景图片


class ModeButton(ButtonGame):
    """创建各种功能按钮"""

    def __init__(self, x, y, screen, list_image):
        super().__init__(x, y, screen, list_image)
        self.image_size = []
        self.button_make = False  # 创建一个按钮图片替换的开关
        for image1 in self.images:
            self.image_size.append(image1.get_rect())  # 获取图片的外接矩形

    def mouse_make(self, mouse_x, mouse_y):
        """根据光标位置控制显示的方法"""
        # 如果光标的坐标在图片按钮的范围之内
        if self.x <= mouse_x <= self.x + self.image_size[0].w \
                and self.y <= mouse_y <= self.y + self.image_size[0].h:
            self.button_make = True  # 显示黄色的图片
        else:
            self.button_make = False  # 显示绿色的图片

    def draw(self):  # 重写显示方法
        try:
            if not self.button_make:  # 如果替换开关是关闭的
                self.screen.blit(self.images[0], (self.x, self.y))  # 显示绿色的图片

            else:
                self.screen.blit(self.images[1], (self.x, self.y))  # 显示黄色的图片

        except Exception as re:
            print(re)


class Beijing(Obj):
    """创建一个背景类"""
    def __init__(self, x, y, screen, filename):
        super().__init__(x, y, screen, filename)
        self.num = -2000  # 设置图片最初位置

    def draw(self):  # 重写父类的方法
        if self.name == st.BEIJING_1:  # 如果是游戏战斗背景图
            self.y = self.num
            self.num += st.BEIJING_SPEED  # 使得背景图移动
            if self.num > -10:
                self.num = -2000
        self.screen.blit(self.image_1, (self.x, self.y))  # 循环显示背景图片


class Factory(object):
    """"创建一个万能的工厂，能够生产并自动将其添加到显示列表"""
    @staticmethod
    def beijing_act(x, y, screen, filename):
        """创造并显示静态的图片"""
        beijing = Beijing(x, y, screen, filename)
        screen_list.append(beijing)  # 将背景添加到显示列表
        return beijing

    @staticmethod
    def script_act(x, y, screen, script, size,
                   filename=st.SCRIPT2, num=0, color=(255, 0, 0),
                   bool_sc=True, bg_script=None):
        """创建一个柔性化制造各种效果文字的工厂"""
        ls = [x, y, screen, script, size,
              filename, color, bool_sc, bg_script
              ]
        if num == 0:  # 如果选择为0则创建基本的文字
            script = ScriptNew(*ls)

        elif num == 1:  # 如果选择为1则创建大小变化的文字
            script = ScriptMove(*ls)
        elif num == 2:
            script = ScriptEnd(*ls)  # 创建小变大的文字
        elif num == 3:
            script = ScriptLong(*ls)  # 创建长文字
        screen_list.append(script)  # 添加文字到显示列表
        return script

    @staticmethod
    def button1_act(x, y, screen, list_image):
        """创建普通按钮"""
        button = ModeButton(x, y, screen, list_image)
        screen_list.append(button)
        return button

    @staticmethod
    def button_act(x, y, screen, list_image):
        """按钮生成器"""
        button = ButtonGame(x, y, screen, list_image)
        screen_list.append(button)

    @staticmethod
    def star_act(x, y, screen, filename):
        """流星雨生成器"""
        show = Star(x, y, screen, filename)
        screen_list.append(show)

    @staticmethod
    def hreo_act(x, y, screen, filename):
        """生产我方的飞机"""
        my_plane = Hreo(x, y, screen, filename)
        screen_list.append(my_plane)
        return my_plane

    @staticmethod
    def any_blast(target1, blast_name, btitem=1):
        """爆炸的公共方法"""
        if btitem == 1:  # 如果选择短爆炸
            bst = SmallBlast(target1, blast_name)  # 创建一个爆炸的对象
        else:  # 长爆炸
            bst = LongBlast(target1, blast_name)  # 创建一个爆炸的对象
        screen_list.append(bst)  # 将爆炸效果添加到显示列表

    @staticmethod
    def boss_blast(element):
        """boss飞机爆炸的公共方法"""
        for i in range(0, 4):
            ran = random.randint(0, 4)  # 随机生成位置
            bst = LongBlast(element, 'big', -16 + 40*ran, -150 + i*40)
            screen_list.append(bst)

    @staticmethod
    def buff_act(ele, prob):
        """buff生成方法"""
        ran = random.randint(0, 10)   # 有一定概率出现buff
        if ran < prob:  # 调整概率
            buff = BuffBullet1(ele.x, ele.y, ele.screen, random.choice(st.LIST_BUFF))
            screen_list.append(buff)  # 添加到显示列表

    @staticmethod
    def music_act(name):
        """音乐播放方法"""
        music1 = MusicThis(name)
        music1.play_music()
        del music1

    @staticmethod
    def enemy_act(x, y, screen, filename):
        """创建一个敌方飞机的生产线"""
        if filename == st.ENEMY_3:  # 如果生产的是敌方boss飞机
            enemy = BossEnemy(x, y, screen, filename)
        else:  # 如果是其他的飞机
            enemy = EnemyPlane(x, y, screen, filename)
        screen_list.append(enemy)  # 添加到显示列表
        return enemy

    @staticmethod
    def bullet_act(element):
        bullets = []  # 子弹初始值为空
        """生产子弹"""
        if isinstance(element, Hreo):  # 如果发射子弹的是我方
            if st.GOD_BUFF:  # 如果金币buff开关打开
                bullet = GodBullet(element, 0, 0)
                bullets.append(bullet)
            elif st.LASER_BUFF:  # 如果是激光子弹开关打开
                for i in range(-1, 2):  # 创建3颗子弹
                    bullet = LaserBullet(element, i*40, 0)
                    bullets.append(bullet)
            elif st.RAN_BUFF:  # 如果是随机运动的子弹
                for i in range(0, 2):
                    bullet = RanBullet(element, -32 + i*64, 0)
                    bullets.append(bullet)
            else:  # 螺旋子弹
                bullet = LuoXBullet(element)
                bullets.append(bullet)

        elif isinstance(element, EnemyPlane):  # 若果放射子弹的是敌方
            if isinstance(element, BossEnemy):  # 如果是boss飞机
                for i in range(-1, 2):  # 创建3颗子弹
                    bullet = EneBullet(element, i*32, 0)
                    bullets.append(bullet)
            else:  # 如果是普通飞机
                bullet = EneBullet(element, 0, 0)
                bullets.append(bullet)

        else:
            bullet = EneBullet(element, 0, 0)
            bullets.append(bullet)
        if bullets:  # 如果不为空
            bullet_list.extend(bullets)


class Hreo(Obj):
    """创建一个我方飞机类"""

    def __init__(self, x, y, screen, filename):
        super().__init__(x, y, screen, filename)
        self.speed = st.HERO_SPEED  # 飞机的速度
        self.__blood = st.HERO_BLOOD   # 设置血量
        self.button_fire = False  # 一个控制开火的开关

    @property
    def blood(self):
        """创建血量访问方法"""
        return self.__blood

    @blood.setter
    def blood(self, new_blood):
        """血量设置方法"""
        self.__blood = new_blood

    def __del__(self):
        self.button_fire = False  # 关闭开火
        print("hero删除执行了")

    def get_fire(self):  # 设置类方法访问和修改类属性
        return self.button_fire

    def set_fire(self, bools):
        self.button_fire = bools

    def fire(self):
        """发射子弹"""
        Factory.music_act(st.FIRE_MUSIC)  # 播放音乐
        Factory.bullet_act(self)  # 调用工厂产生子弹并发射出去

    def hreo_move(self, strx):
        """飞机移动的方法"""
        if strx == 'up':  # 向上移动
            self.y -= self.speed
        elif strx == 'down':  # 向下移动
            self.y += self.speed
        elif strx == 'left':  # 向左移动
            self.x -= self.speed
        elif strx == 'right':  # 向右移动
            self.x += self.speed
        else:
            pass

    def ishit(self, ele):
        """飞机的碰撞检测执行函数"""
        # 忽略所有子弹、背景、爆炸图、本身、文字
        if isinstance(ele, (Beijing, Blast, Hreo, Bullet, ScriptBase)):
            # print("这是背景或本身")
            return False

        result = any_hit(self, ele)  # 调用公共方法检测碰撞

        if result:
            if isinstance(ele, EnemyPlane):  # 如果碰到敌方飞机
                # print("撞上了！")
                if ele.name == st.ENEMY_1:
                    self.__bloods(ele, 50, "big")
                elif ele.name == st.ENEMY_2:
                    self.__bloods(ele, 100, "big", btm=2)
                elif ele.name == st.ENEMY_3:
                    self.blood -= 5  # 自身血量减少
                    ele.blood -= 5  # boss血量减少5

            if isinstance(ele, BuffBullet1):  # 如果碰到的是buff
                bullet_del.append(ele)  # buff1消失
                ele.buff_creat()  # 调用方法产生效果

            if isinstance(ele, Stony):  # 如果碰到的是陨石
                self.__bloods(ele, 500, "big", 2)

    def __bloods(self, ele, blood_r, name, btm=1):
        """检测血量"""
        self.__blood -= blood_r  # 自身血量减少
        Factory.any_blast(ele, name, btm)  # 敌方飞机爆炸并删除
        bullet_del.append(ele)  # 删除敌方飞机

    def draw(self):  # 重写父类的方法
        self.screen.blit(self.image_1, (self.x, self.y))  # 显示我方飞机
        for ele in screen_list:  # 遍历显示列表检测碰撞
            # print(ele)
            self.ishit(ele)

        self.serc()  # 越界和血量检测

    def serc(self):
        """血量和越界检测"""
        if self.__blood <= 0:  # 如果血量少于0删除自己
            Factory.any_blast(self, 'big', 2)  # 产生爆炸
            self.button_fire = False  # 关闭开火开关
            # 创建“你输了”文字
            Factory.script_act(70, 250, self.screen, "你输了", 100, num=2)
            bullet_del.append(self)

        # 越界检测
        if self.x <= 0:
            self.x = 0
        elif self.x >= 540:
            self.x = 540
        if self.y <= 0:
            self.y = 0
        elif self.y >= 600:
            self.y = 600


class Bullet(Obj):
    """创建子弹类"""
    def __init__(self, element):
        self.screen = element.screen
        self.ele = element
        self.name = None
        self.image_bullet = None
        self.bullet_speed = None
        self.__blood = 50  # 设置血量

    def bullet_init(self, x1, y1, speed):
        """不同子弹初始化参数的函数"""
        self.x = self.ele.x + x1
        self.y = self.ele.y + y1
        self.image_bullet = pygame.image.load_extended(self.name)  # 加载背景图片
        self.rect = self.image_bullet.get_rect()   # 获得图片的尺寸
        self.bullet_speed = speed  # 设置子弹的速度

    @property
    def blood(self):
        """创建血量访问方法"""
        return self.__blood

    @blood.setter
    def blood(self, new_blood):
        """血量设置方法"""
        self.__blood = new_blood

    def draw(self):
        """
        修改数字，不要使用计数器来降低子弹的速度，因为计数器作为一个公共变量，
        不同的子弹数据会造成干扰，导致子弹移动出现问题
        """
        self.screen.blit(self.image_bullet, (self.x, self.y))   # 绘制子弹
        for ele in screen_list:  # 遍历显示列表检测碰撞
            # print(ele)
            self.ishit(ele)
        self.bullet_move()  # 子弹的移动

    def bullet_move(self):
        """子弹移动的函数"""
        if isinstance(self.ele, Hreo):  # 判断是那种飞机的子弹
            self.y -= self.bullet_speed
        else:
            self.y += self.bullet_speed
        self.bullet_out()  # 子弹越界检测

    def bullet_out(self):
        """判断子弹越界"""
        if self.y < -30 or self.y > 704:  # 判断子弹是否越界
            bullet_del.append(self)

    def ishit(self, ele):
        """子弹的碰撞检测函数"""
        # 忽略掉子弹本身、背景、爆炸、buff子弹
        if ele is self or isinstance(ele, (Beijing, Blast, BuffBullet1, ScriptBase)):
            # print("这是背景或本身")
            return False

        # 若果是我方飞机产生的子弹或流星雨产生的子弹
        if isinstance(self.ele, (Hreo, Star)):
            result = any_hit(self, ele)
            # 忽略本类对象
            if isinstance(ele, Bullet) and isinstance(ele.ele, (Hreo, Star)):
                return False
            else:
                if result:  # 发生了碰撞
                    # print("撞上了")
                    # 如果碰撞到敌方子弹
                    if isinstance(ele, Bullet) and isinstance(ele.ele, EnemyPlane):
                        self.hit_result(ele, "xiao")  # 调用效果函数
                    # 如果碰到的是敌方小飞机
                    elif ele.name == st.ENEMY_1 and isinstance(ele, EnemyPlane):
                        self.hit_result(ele)   # 调用效果函数
                    # 如果碰到的是敌方大飞机
                    elif ele.name == st.ENEMY_2 and isinstance(ele, EnemyPlane):
                        self.hit_result(ele, "big", 2)
                    # 如果是boss飞机
                    elif ele.name == st.ENEMY_3 and isinstance(ele, EnemyPlane):
                        self.hit_result(ele, 'big', 2)
                    # 如果碰到的是陨石
                    elif isinstance(ele, Stony):
                        self.hit_result(ele, "big", 2)
                        Factory.buff_act(ele, 1)  # 每次碰撞爆buff概率为10%

        else:  # 如果是敌方飞机产生的子弹
            result = any_hit(self, ele)
            if not isinstance(ele, Hreo):   # 忽略除了英雄飞机外的所有对象
                return False
            else:
                if result:  # 发生了碰撞
                    # print("撞上了")
                    self.hit_result(ele, "big", 2)  # 调用效果函数

    def hit_result(self, ele, blast_name="big", btm=1):
        """碰撞后产生的效果函数"""
        if self.__blood >= ele.blood:  # 如果子弹血量大于对方血量
            self.__blood -= ele.blood
            ele.blood = -1
        else:
            ele.blood -= self.blood
            self.__blood = 0
            bullet_del.append(self)

        if ele.blood > 0:  # 若果对方血量还大于0，产生小爆炸
            Factory.any_blast(ele, 'xiao')  # 产生一个小短爆炸效果
        else:  # 如果对方血量小于0，产生大爆炸，同时删除对方飞机
            if isinstance(ele, BossEnemy):  # 如果对方是boss飞机
                # 创建“你赢了”文字
                Factory.script_act(70, 250, self.screen, "你赢了", 100, num=2)
            else:
                Factory.any_blast(ele, blast_name, btm)
            bullet_del.append(ele)  # 将对方添加到删除列表

            if isinstance(ele, EnemyPlane):  # 如果是敌机被打爆，则敌机死亡计数器加1
                ele.set_enemy_die()

            if not isinstance(ele, Bullet):  # 如果对方不是子弹才能产生buff
                if isinstance(ele, Stony):  # 对方陨石爆炸
                    Factory.buff_act(ele, 5)  # 爆buff概率为30%
                else:  # 其他的爆炸
                    Factory.buff_act(ele, 3)  # 爆buff概率为20%


class RanBullet(Bullet):
    """创建随机跳弹"""
    def __init__(self, element, x1, y1):
        super().__init__(element)
        self.name = st.RAN_BULLET  # 得到子弹的图片作为名字
        self.__blood = 50  # 设置血量
        self.fps = 0  # 子弹移动换方向的时间
        self.ran = 0  # 子弹左右的方向
        if isinstance(self.ele, Hreo):  # 我方飞机
            self.bullet_init(48 + x1, -64 + y1, st.BULLET_SPEED+2)

    def bullet_move(self):
        """重写子弹移动的函数"""
        if isinstance(self.ele, Hreo):  # 判断是那种飞机的子弹
            self.y -= self.bullet_speed  # 向上运动
            self.fps += 1
            if self.fps % 10 == 0:  # 每10帧数改变方向
                self.ran = random.randint(0, 1)
            if self.ran == 0:
                self.x -= self.bullet_speed - 5
            else:
                self.x += self.bullet_speed - 5

        self.bullet_out()  # 子弹越界检测


class GodBullet(Bullet):
    """创建一个金币子弹类"""
    def __init__(self, element, x1, y1):
        super().__init__(element)
        self.name = st.GOD_BULLET  # 得到子弹的图片作为名字
        self.__blood = 200  # 设置血量
        if isinstance(self.ele, Hreo):  # 我方飞机
            self.bullet_init(25 + x1, -30 + y1, st.BULLET_SPEED+2)


class LaserBullet(Bullet):
    """创建激光子弹"""
    def __init__(self, element, x1, y1):
        super().__init__(element)
        self.name = st.LASER_BULLET  # 得到子弹的图片作为名字
        self.__blood = 100  # 设置血量
        if isinstance(self.ele, Hreo):  # 我方飞机
            self.bullet_init(40 + x1, -90 + y1, st.BULLET_SPEED)


class LuoXBullet(Bullet):
    """创建螺旋子弹"""
    def __init__(self, element):
        super().__init__(element)
        self.name = st.LUOXUAN_BULLET  # 得到子弹的图片作为名字
        self.__blood = 50  # 设置血量
        if isinstance(self.ele, Hreo):  # 我方飞机
            self.bullet_init(42, -20, st.BULLET_SPEED)


class EneBullet(Bullet):
    """创建普通子弹"""
    def __init__(self, element, x1, y1):
        super().__init__(element)
        self.name = st.MY_BULLET  # 得到子弹的图片作为名字
        self.__blood = 50  # 设置血量

        if isinstance(self.ele, EnemyPlane):  # 如果是敌机
            if self.ele.name == st.ENEMY_1:  # 敌方小飞机
                self.bullet_init(16 + x1, 32 + y1, st.BULLET_SPEED - 3)
            elif self.ele.name == st.ENEMY_2:  # 敌方中型飞机
                self.bullet_init(24 + x1, 64 + y1, st.BULLET_SPEED - 3)
            elif self.ele.name == st.ENEMY_3:  # 敌方boss飞机
                self.bullet_init(72 + x1, 220 + y1, st.BULLET_SPEED)

        if isinstance(self.ele, Star):  # 如果是流星雨
                self.bullet_init(x1, y1, st.BULLET_SPEED)


class Star(Obj):
    """一个下流星雨的类"""
    __button1 = None  # 创建控制单例模式开关
    __button2 = True

    def __init__(self, x, y, screen, filename):
        if self.__button2:
            super().__init__(x, y, screen, filename)
            self.fps = 0  # 创建时间计数
            self.num_shower = 0  # 创建流星雨下的次数计数
            # self.button_star = False  # 下雨的开关
            self.__button2 = False  # 保证只有一次初始化

    def __new__(cls, *args, **kwargs):
        if not cls.__button1:
            cls.__button1 = Obj.__new__(cls)
        return cls.__button1

    def draw(self):
        if st.SHOWER_BUFF:
            self.fps += 1
            if self.fps % 60 == 0:
                self.num_shower += 1
                for i in range(10):
                    bullet_new = EneBullet(self, i * 64, -32)
                    screen_list.append(bullet_new)  # 添加到显示列表
                # 五次后关闭流星雨
                if self.num_shower > 3:
                    self.fps = 0
                    self.num_shower = 0
                    st.SHOWER_BUFF = False


class Blast(Obj):
    """创建一个爆炸效果类"""
    def __init__(self, ele, name):
        self.num1 = 0
        self.screen = ele.screen
        self.name = name
        self.image_blast = []

        # 如果是敌机的子弹爆炸
        if isinstance(ele, Bullet) and not isinstance(ele.ele, Hreo):
            self.x = ele.x - 56
            self.y = ele.y - 32
        # 如果是敌方的小飞机爆炸
        elif ele.name == st.ENEMY_1 and isinstance(ele, EnemyPlane):
            self.x = ele.x - 40
            self.y = ele.y - 40
        # 如果是敌方的中型飞机爆炸
        elif ele.name == st.ENEMY_2 and isinstance(ele, EnemyPlane):
            self.x = ele.x - 32
            self.y = ele.y - 32
        # 如果是敌方的boss飞机爆炸
        elif ele.name == st.ENEMY_3 and isinstance(ele, BossEnemy):
            self.x = ele.x + 16
            self.y = ele.y + 150
        # 如果是我方飞机爆炸
        elif ele.name == st.HREO_1 and isinstance(ele, Hreo):
            self.x = ele.x - 14
            self.y = ele.y
        # 如果是文字
        elif isinstance(ele, ScriptBase):
            self.x = ele.x
            self.y = ele.y
        else:
            self.x = ele.x - 32
            self.y = ele.y - 32

        Factory.music_act(st.BLAST_MUSIC)  # 播放音乐

    def draw(self):
        pass

    def numx(self, n):
        """改变爆炸的大小"""
        if self.num1 > n:
            self.num1 = 0
            bullet_del.append(self)  # 爆炸完成后删除本身


class SmallBlast(Blast):
    """创建短爆炸"""

    def __init__(self, ele, name):
        super().__init__(ele, name)
        for image in st.LIST_BLAST:   # 加载爆炸图片资源
            self.image_blast.append(pygame.image.load_extended(image))

    def draw(self):  # 重写爆炸绘制方法
        self.screen.blit(self.image_blast[self.num1], (self.x, self.y))
        self.num1 += 1
        if self.name == "xiao":
            self.numx(3)
        elif self.name == "big":
            self.numx(7)


class LongBlast(Blast):
    """创建长爆炸"""
    def __init__(self, ele, name, x=0, y=0):
        super().__init__(ele, name)
        self.x += x
        self.y += y
        for image in st.LIST_BLAST_BIG:   # 加载爆炸图片资源
            self.image_blast.append(pygame.image.load_extended(image))

    def draw(self):
        """绘制长爆炸"""
        self.screen.blit(self.image_blast[self.num1], (self.x, self.y))
        self.num1 += 1
        if self.name == 'xiao':
            self.numx(7)
        elif self.name == 'big':
            self.numx(13)


class EnemyPlane(Obj):
    """创建一个敌方的飞机类1"""
    __enemy_die = 0  # 创建一个类属性记录杀死的敌机数量

    @classmethod
    def get_enemy_die(cls):  # 访问类属性方法
        return cls.__enemy_die

    @classmethod
    def set_enemy_die(cls, num=False):  # 设置类属性方法
        if num:
            cls.__enemy_die = 0  # 重新设置为0
        else:
            cls.__enemy_die += 1

    def __init__(self, x, y, screen, filename):
        super().__init__(x, y, screen, filename)
        self.button_fire = True  # 设置一个是否可以开火的开关
        self.derc = None  # 初始方向为向右
        self.time2 = time.time()  # 时间变量
        if self.name == st.ENEMY_1:  # 如果是敌方小飞机
            self.__blood = st.Small_Blood
            self.enemy_speed1 = st.ENEMY_DOWN_SPEED  # 小飞机设置成快速
        elif self.name == st.ENEMY_2:
            self.__blood = st.Middle_Blood
            self.enemy_speed1 = st.ENEMY_DOWN_SPEED1  # 中型飞机设置成中速
        elif self.name == st.ENEMY_3:
            self.__blood = st.Boss_Blood
            self.enemy_speed1 = st.ENEMY_DOWN_SPEED  # boss飞机设置成慢速

    @property
    def blood(self):
        """创建血量访问方法"""
        return self.__blood

    @blood.setter
    def blood(self, new_blood):
        """血量设置方法"""
        self.__blood = new_blood

    def __del__(self):
        self.button_fire = False  # 关闭开火的开关
        # print("敌机删除执行！")

    def enemy_shoot(self):  # 敌机发射子弹的方法
        ran = random.randint(0, 100)  # 敌机随机发射子弹
        if ran == 80:
            Factory.bullet_act(self)  # 调用工厂生产和装填子弹

    def draw(self):
        # 绘制敌机
        self.screen.blit(self.image_1, (self.x, self.y))
        self.enemy_move()  # 敌机移动
        if self.button_fire:  # 如果开火的开关是打开的
            self.enemy_shoot()  # 敌机发射子弹
        if self.__blood <= 0:  # 小于0删除自身
            bullet_del.append(self)

    def enemy_move(self):  # 使得敌方飞机移动
        """敌机移动的方法"""
        time1 = time.time()  # 敌机每隔1.5秒改变方向
        # print(timex)
        # print(time1 - timex)
        if time1 - self.time2 > 1.5:
            self.time2 = time1
            self.derc = random.randint(0, 3)  # 获取敌机移动的方向

        self.y += self.enemy_speed1  # 使得敌机保持向下，左右随机移动
        if self.derc == 0:
            self.x += st.ENEMY_LR_SPEED
        elif self.derc == 1:
            self.x -= st.ENEMY_LR_SPEED
        self.out_screen()  # 防止敌机左右出界
        self.go_screen()  # 防止敌机下出界

    def out_screen(self):
        """防止敌机左右出界"""
        if self.x <= 0:
            self.x = 0
        elif self.name == st.ENEMY_1 and self.x >= 592:  # 小飞机
            self.x = 592
        elif self.name == st.ENEMY_2 and self.x >= 576:  # 中飞机
            self.x = 576
        elif self.name == st.ENEMY_3 and self.x >= 480:  # boss飞机
            self.x = 480

    def go_screen(self):
        """敌机下出界删除"""
        if self.y > 710:
            bullet_del.append(self)


class BossEnemy(EnemyPlane):
    """创建敌方boss飞机类"""

    def __init__(self, x, y, screen, filename):
        super().__init__(x, y, screen, filename)
        self.time3 = time.time()  # 用来记录换方向的初始时间
        self.button_fire = False  # 开火的开关初始状态设为关闭

    def enemy_shoot(self):
        """重写父类发射子弹的方法"""
        ran = random.randint(0, 100)  # 敌机随机发射子弹
        if ran <= 10:  # 10%的时间发射子弹
            Factory.bullet_act(self)  # 调用工厂生产和装填子弹

    def enemy_move(self):
        """boss移动"""
        time1 = time.time()  # 记录boss移动的时间
        time3 = time.time()  # boss左右换方向的时间
        # print(timex)
        # print(time1 - timex)
        if time1 - self.time2 < 6:  # 如果小于六秒就一直向下移动
            self.y += self.enemy_speed1
        else:  # 大于6秒开始左右移动
            self.button_fire = True  # 打开开火的开关
            if time3 - self.time3 >= 2:
                self.time3 = time3
                while True:
                    derc = random.randint(0, 6)  # 获取敌机移动的方向
                    if self.derc != derc:
                        self.derc = derc
                        break

            if self.derc == 0:  # 向右边移动
                self.x += st.ENEMY_LR_SPEED + 3
            elif self.derc == 1:  # 向左移动
                self.x -= st.ENEMY_LR_SPEED + 3
            elif self.derc == 2:  # 向右弧形移动
                self.x += st.ENEMY_LR_SPEED + 3
                self.y += st.ENEMY_LR_SPEED + 3
            elif self.derc == 3:  # 向右边移动
                self.x += st.ENEMY_LR_SPEED + 3
                self.y -= st.ENEMY_LR_SPEED + 3
            elif self.derc == 4:  # 向左边移动
                self.x -= st.ENEMY_LR_SPEED + 3
                self.y += st.ENEMY_LR_SPEED + 3
            elif self.derc == 5:  # 向左上移动
                self.x -= st.ENEMY_LR_SPEED + 3
                self.y -= st.ENEMY_LR_SPEED + 3
            self.go_screen1()  # 防止上出界
        self.out_screen()  # 防止敌机左右出界
        self.go_screen()  # 防止敌机下出界

    def go_screen1(self):
        """防止敌机上出界"""
        if self.y <= 0:
            self.y = 0

    def go_screen(self):
        """防止敌机下出界"""
        if self.y >= 448:
            self.y = 448

    def draw(self):
        super().draw()
        if self.blood <= 0:
            Factory.boss_blast(self)  # 创建超极爆炸
            bullet_del.append(self)


class MusicThis(object):
    """创建一个音乐类管理音乐"""
    def __init__(self, filename, count=0):
        self.filename = filename
        self.count = count

    def play_music(self):
        """播放音乐"""
        pygame.mixer_music.load(self.filename)  # 添加音乐
        pygame.mixer_music.play(self.count)  # 播放音乐


class BuffBullet1(Obj):
    """创建一个子弹外挂管理的类"""
    def __init__(self, x, y, screen, filename):
        super().__init__(x, y, screen, filename)
        self.time = 0  # 设置一个计时器

    def buff_creat(self):
        """buff的开关控制"""
        if self.name == st.BUFF_1:  # 如果是流星雨buff
            st.SHOWER_BUFF = True  # 打开开关，在主函数中显示
            Factory.star_act(0, 0, self.screen, st.MY_BULLET)

        elif self.name == st.BUFF_2:  # 如果是金币子弹buff
            self.buff_control(n2=True)
            st.BUFF_TIME = 0  # 将金币buff时间计数器设为0

        elif self.name == st.BUFF_3:  # 如果是激光子弹buff
            self.buff_control(n3=True)
            st.LASER_TIME = 0  # 将buff时间计数器设为0

        elif self.name == st.BUFF_4:  # 如果是随机弹
            # 随机弹开关打开，其他的关闭
            BuffBullet1.buff_control(n1=True)
            st.RAN_TIME = 0  # 将时间计数器设为0

    @staticmethod
    def buff_control(n1=False, n2=False, n3=False):
        """创建管理子弹buff开关打开的函数"""
        st.RAN_BUFF = n1  # 随机弹开关
        st.GOD_BUFF = n2  # 金币子弹buff开关
        st.LASER_BUFF = n3  # 激光子弹buff开关

    def draw(self):
        # 循环显示背景图
        self.screen.blit(self.image_1, (self.x, self.y))
        self.y += st.BUFF_SPEED  # buff移动
        self.time += 1
        if self.time > 400:  # buff超过6秒后自动删除
            bullet_del.append(self)
            self.time = 0
        if self.y < -30 or self.y > 704:  # 判断buff是否越界
            bullet_del.append(self)


class Stony(Obj):
    """创建一个陨石类"""
    def __init__(self, x, y, screen, filename):
        """定义构造属性"""
        super().__init__(x, y, screen, filename)
        self.drec = random.randint(0, 1)  # 创建一个移动的左右随机方向
        self.__blood = 500  # 设置血量

    @property
    def blood(self):
        """创建血量访问方法"""
        return self.__blood

    @blood.setter
    def blood(self, new_blood):
        """血量设置方法"""
        self.__blood = new_blood

    def draw(self):
        # 循环显示背景图
        self.screen.blit(self.image_1, (self.x, self.y))
        if self.__blood <= 0:  # 血量小于0
            bullet_del.append(self)
        self.y += st.STONY_SPEED  # 移动
        if self.drec == 0:
            self.x += st.STONY_SPEED - 4.2
        else:
            self.x -= st.STONY_SPEED - 4.2
        # 判断是否越界
        if self.y < -150 or self.y > 750 or self.x < -100 or self.x > 640:
            bullet_del.append(self)
